package com.advertisementsystem.Servie.Impl;

import com.advertisementsystem.Dto.LoginUser;
import com.advertisementsystem.Dto.ScheduleDTO;
import com.advertisementsystem.Dto.ScheduleUpdateDTO;
import com.advertisementsystem.Dto.TimeSlot;
import com.advertisementsystem.Exception.BusinessException;
import com.advertisementsystem.Mapper.AdNegotiationMapper;
import com.advertisementsystem.Mapper.AdScheduleMapper;
import com.advertisementsystem.Mapper.AdvertisementMapper;
import com.advertisementsystem.Mapper.DeviceMapper;
import com.advertisementsystem.Servie.*;
import com.advertisementsystem.entity.*;
import com.advertisementsystem.handler.ChatWebSocketHandler;
import com.advertisementsystem.vo.AdSchedule;
import com.advertisementsystem.vo.ScheduleVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
@Transactional
public class ScheduleServiceImpl implements ScheduleService {

    @Autowired
    private AdScheduleMapper scheduleMapper;

    @Autowired
    private AdvertisementService advertisementService;

    @Autowired
    private DeviceService deviceService;

    private final ObjectMapper objectMapper = new ObjectMapper();
    @Autowired
    private AdvertisementMapper advertisementMapper;

    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private AdNegotiationMapper adNegotiationMapper;

    @Autowired
    private ChatWebSocketHandler handler;

    @Autowired
    private NotificationService notificationService;


    @Autowired
    private UserService userService;
    @Override
    public Schedule createSchedule(ScheduleDTO dto) {
        // 验证广告和设备
        validateAdvertisementAndDevice(dto.getAdvertisementId(), dto.getDeviceId());
        // 验证时间段
        validateTimeSlots(dto.getTimeSlots());
        // 检查时间冲突
        checkTimeConflict(dto.getDeviceId(), dto.getStartTime(), dto.getEndTime(),
                dto.getTimeSlots(), null);
        // 创建排期
        Schedule schedule = new Schedule();
        BeanUtils.copyProperties(dto, schedule);
        schedule.setStatus("PENDING");
        schedule.setCreatedTime(LocalDateTime.now());
        schedule.setUpdatedTime(LocalDateTime.now());
        schedule.setNegotiationId(dto.getNegotiationId());
        scheduleMapper.insert(schedule);
        LambdaQueryWrapper<AdNegotiation> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AdNegotiation::getAdId, dto.getAdvertisementId())
                .eq(AdNegotiation::getDeviceId, dto.getDeviceId())
                .eq(AdNegotiation::getStatus, 0);
        AdNegotiation negotiation = adNegotiationMapper.selectOne(wrapper);
        negotiation.setTimeSlots(dto.getTimeSlots());
        adNegotiationMapper.updateById(negotiation);


        return schedule;
    }

    private void checkTimeConflict(Long deviceId, LocalDateTime startTime,
                                   LocalDateTime endTime, List<TimeSlot> newTimeSlots,
                                   Long excludeId) {
        // 获取日期范围内的所有排期
        LambdaQueryWrapper<Schedule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Schedule::getDeviceId, deviceId)
                .and(w -> w.eq(Schedule::getStatus, "PENDING")
                        .or()
                        .eq(Schedule::getStatus, "RUNNING"))
                .and(w -> w
                        .between(Schedule::getStartTime, startTime, endTime)
                        .or()
                        .between(Schedule::getEndTime, startTime, endTime))
                .ne(excludeId != null, Schedule::getId, excludeId);

        List<Schedule> existingSchedules = scheduleMapper.selectList(wrapper);

        // 检查每个现有排期的时间段是否与新的时间段冲突
        for (Schedule existing : existingSchedules) {
            if (hasTimeSlotConflict(newTimeSlots, existing.getTimeSlots())) {
                throw new BusinessException("该时间段已有其他广告排期");
            }
        }
    }

    private boolean hasTimeSlotConflict(List<TimeSlot> newTimeSlots, Object existingTimeSlotsObj) {
        List<Map<String, String>> existingTimeSlots;

        try {
            // 将现有的时间段转换为Map列表
            if (existingTimeSlotsObj instanceof List) {
                existingTimeSlots = objectMapper.convertValue(existingTimeSlotsObj,
                        new TypeReference<List<Map<String, String>>>() {});
            } else {
                log.error("时间段数据格式不正确: {}", existingTimeSlotsObj);
                return false; // 或者根据您的业务逻辑决定返回 true
            }

            // 检查每个新时间段是否与现有时间段重叠
            for (TimeSlot newSlot : newTimeSlots) {
                LocalTime newStart = LocalTime.parse(newSlot.getStartTime());
                LocalTime newEnd = LocalTime.parse(newSlot.getEndTime());

                for (Map<String, String> existingSlot : existingTimeSlots) {
                    LocalTime existingStart = LocalTime.parse(existingSlot.get("startTime"));
                    LocalTime existingEnd = LocalTime.parse(existingSlot.get("endTime"));

                    // 检查时间段是否重叠
                    if (!(newEnd.isBefore(existingStart) || newStart.isAfter(existingEnd))) {
                        return true; // 有重叠
                    }
                }
            }

            return false; // 没有重叠
        } catch (Exception e) {
            log.error("解析时间段失败: {}", e.getMessage(), e);
            // 发生异常时，可以选择返回 true 以避免出现错误的时间段
            return true;
        }
    }
    private boolean isTimeSlotOverlap(TimeSlot slot1, TimeSlot slot2) {
        LocalTime start1 = LocalTime.parse(slot1.getStartTime());
        LocalTime end1 = LocalTime.parse(slot1.getEndTime());
        LocalTime start2 = LocalTime.parse(slot2.getStartTime());
        LocalTime end2 = LocalTime.parse(slot2.getEndTime());

        return !(end1.isBefore(start2) || start1.isAfter(end2));
    }
    // 新增一个接受Map参数的方法
    private boolean isTimeSlotOverlap(TimeSlot slot1, Map<String, String> slot2) {
        LocalTime start1 = LocalTime.parse(slot1.getStartTime());
        LocalTime end1 = LocalTime.parse(slot1.getEndTime());
        LocalTime start2 = LocalTime.parse(slot2.get("startTime"));
        LocalTime end2 = LocalTime.parse(slot2.get("endTime"));

        return !(end1.isBefore(start2) || start1.isAfter(end2));
    }
    @Override
    public List<Schedule> getDeviceSchedule(Long deviceId, LocalDate startDate, LocalDate endDate) {
        // 验证设备是否存在
        deviceService.getDeviceDetail(deviceId);

        LocalDateTime startDateTime = startDate.atStartOfDay();
        LocalDateTime endDateTime = endDate.atTime(23, 59, 59);

        return scheduleMapper.findByDeviceIdAndDateRange(deviceId, startDateTime, endDateTime);
    }

    @Override
    public List<ScheduleVo> getAdvertisementSchedule(Long adId) {
        // 验证广告是否存在
        advertisementService.getAdvertisementDetail(adId);
        List<Schedule> schedule = scheduleMapper.findByAdvertisementId(adId);
        List<ScheduleVo> scheduleVo = new ArrayList<>();
        for (Schedule s : schedule) {
            ScheduleVo vo = new ScheduleVo();
            BeanUtils.copyProperties(s, vo);
            vo.setDeviceName(deviceService.getDeviceDetail(s.getDeviceId()).getName());
            scheduleVo.add(vo);
        }

        return scheduleVo;
    }

    @Override
    public Schedule updateSchedule(Long id, ScheduleUpdateDTO dto) {
        Schedule schedule = scheduleMapper.selectById(id);
        if (schedule == null) {
            throw new BusinessException("排期不存在");
        }

        // 如果更新了时间段，验证时间段
        List<TimeSlot> newTimeSlots = dto.getTimeSlots() != null ?
                dto.getTimeSlots() : schedule.getTimeSlots();
        if (dto.getTimeSlots() != null) {
            validateTimeSlots(newTimeSlots);
        }

        // 如果更新了时间或时间段，检查冲突
        if (dto.getStartTime() != null || dto.getEndTime() != null || dto.getTimeSlots() != null) {
            LocalDateTime newStartTime = dto.getStartTime() != null ?
                    dto.getStartTime() : schedule.getStartTime();
            LocalDateTime newEndTime = dto.getEndTime() != null ?
                    dto.getEndTime() : schedule.getEndTime();

            checkTimeConflict(schedule.getDeviceId(), newStartTime, newEndTime,
                    newTimeSlots, id);
        }

        // 更新字段
        if (dto.getStartTime() != null) schedule.setStartTime(dto.getStartTime());
        if (dto.getEndTime() != null) schedule.setEndTime(dto.getEndTime());
        if (dto.getTimeSlots() != null) schedule.setTimeSlots(dto.getTimeSlots());
        if (dto.getRemark() != null) schedule.setRemark(dto.getRemark());

        schedule.setUpdatedTime(LocalDateTime.now());
        scheduleMapper.updateById(schedule);

        log.info("Updated schedule: {}", schedule.getId());
        return schedule;
    }

    @Override
    public boolean checkNegotiationHasSchedule(Long negotiationId) {
        // 验证协商是否存在
        AdNegotiation negotiation = adNegotiationMapper.selectById(negotiationId);
        if (negotiation == null) {
            log.warn("协商不存在, ID: {}", negotiationId);
            return false;
        }

        // // 验证协商是否已完成
        // if (negotiation.getStatus() != 1) {
        //     log.info("协商未完成，不能创建排期, ID: {}, 状态: {}", negotiationId, negotiation.getStatus());
        //     return false;
        // }

        // 获取协商关联的广告ID和设备ID
        Long advertisementId = negotiation.getAdId();
        Long deviceId = negotiation.getDeviceId();

        // 查询是否存在相关排期
        LambdaQueryWrapper<Schedule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Schedule::getAdvertisementId, advertisementId)
                .eq(Schedule::getDeviceId, deviceId);
        int count = Math.toIntExact(scheduleMapper.selectCount(wrapper));

        boolean hasSchedule = count > 0;
        log.info("协商ID: {}, 是否已创建排期: {}", negotiationId, hasSchedule);

        return hasSchedule;
    }

    @Override
    public Page<Schedule> page(Page<Schedule> page, LambdaQueryWrapper<Schedule> queryWrapper) {
        return  scheduleMapper.selectPage(page, queryWrapper);
    }

    @Override
    public Page<ScheduleVo> getAdvertiserSchedules(Long advertiserId, Integer pageNum, Integer pageSize, String adTitle, String deviceName, String status) {
        // 首先获取该广告主的所有广告ID
        LambdaQueryWrapper<Advertisement> adQueryWrapper = new LambdaQueryWrapper<>();
        adQueryWrapper.eq(Advertisement::getAdvertiserId, advertiserId);

        if (StringUtils.hasText(adTitle)) {
            adQueryWrapper.like(Advertisement::getTitle, adTitle);
        }

        List<Advertisement> advertisements = advertisementMapper.selectList(adQueryWrapper);

        if (advertisements.isEmpty()) {
            // 如果没有广告，返回空结果
            return new Page<>(pageNum, pageSize, 0);
        }

        List<Long> adIds = advertisements.stream()
                .map(Advertisement::getId)
                .collect(Collectors.toList());

        // 构建广告ID到标题的映射
        Map<Long, String> adTitleMap = advertisements.stream()
                .collect(Collectors.toMap(Advertisement::getId, Advertisement::getTitle)); // 查询排期
        Page<Schedule> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Schedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Schedule::getAdvertisementId, adIds)
                .orderByDesc(Schedule::getCreatedTime);

        // 状态过滤
        if (StringUtils.hasText(status)) {
            queryWrapper.eq(Schedule::getStatus, status);
        }

        Page<Schedule> schedulePage = this.page(page, queryWrapper);

        if (schedulePage.getRecords().isEmpty()) {
            return new Page<>(pageNum, pageSize, 0);
        }

        // 获取所有设备ID
        List<Long> deviceIds = schedulePage.getRecords().stream()
                .map(Schedule::getDeviceId)
                .distinct()
                .collect(Collectors.toList());

        // 批量查询设备信息
        LambdaQueryWrapper<Device> deviceQueryWrapper = new LambdaQueryWrapper<>();
        deviceQueryWrapper.in(Device::getId, deviceIds);

        // 如果有设备名称过滤
        if (StringUtils.hasText(deviceName)) {
            deviceQueryWrapper.like(Device::getName, deviceName);
            // 如果设备名称过滤导致没有设备匹配，则返回空结果
            List<Device> filteredDevices = deviceMapper.selectList(deviceQueryWrapper);
            if (filteredDevices.isEmpty()) {
                return new Page<>(pageNum, pageSize, 0);
            }
            // 重新筛选设备ID
            List<Long> filteredDeviceIds = filteredDevices.stream()
                    .map(Device::getId)
                    .collect(Collectors.toList());
            queryWrapper.in(Schedule::getDeviceId, filteredDeviceIds);
            // 重新查询
            schedulePage = this.page(page, queryWrapper);
            if (schedulePage.getRecords().isEmpty()) {
                return new Page<>(pageNum, pageSize, 0);
            }
        }

        List<Device> devices = deviceMapper.selectList(deviceQueryWrapper);
        Map<Long, Device> deviceMap = devices.stream()
                .collect(Collectors.toMap(Device::getId, device -> device));

        // 转换为VO
        Page<ScheduleVo> resultPage = new Page<>(pageNum, pageSize, schedulePage.getTotal());
        List<ScheduleVo> records = schedulePage.getRecords().stream().map(schedule -> {
            ScheduleVo vo = new ScheduleVo();
            BeanUtils.copyProperties(schedule, vo);

            // 设置广告标题
            vo.setAdvertisementTitle(adTitleMap.getOrDefault(schedule.getAdvertisementId(), "未知广告"));

            Device device = deviceMap.get(schedule.getDeviceId());
            if (device != null) {
                vo.setDeviceName(device.getName());
            } else {
                vo.setDeviceName("未知设备");
            }

            return vo;
        }).collect(Collectors.toList());

        resultPage.setRecords(records);

        return resultPage;
    }

    @Override
    public ScheduleVo getScheduleDetailForAdvertiser(Long id, Long advertiserId) {
        // 查询排期
        LambdaQueryWrapper<Schedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Schedule::getId, id);
        Schedule schedule = scheduleMapper.selectOne(queryWrapper);
        if (schedule == null) {
            log.warn("排期不存在，ID: {}", id);
            return null;
        }

        // // 检查排期是否属于该广告主
        Advertisement advertisement = advertisementMapper.selectById(schedule.getAdvertisementId());
        // if (advertisement == null || !advertisement.getAdvertiserId().equals(advertiserId)) {
        //     log.warn("广告主(ID:{})无权查看排期(ID:{})", advertiserId, id);
        //     return null;
        // }

        // 查询设备信息
        Device device = deviceMapper.selectById(schedule.getDeviceId());


        // 组装VO
        ScheduleVo vo = new ScheduleVo();
        BeanUtils.copyProperties(schedule, vo);
        User advertiser = userService.getUserById(advertiserId);
        vo.setAdvertiserName(advertiser.getNickname());
        // 设置广告标题
        vo.setAdvertisementTitle(advertisement.getTitle());

        // 设置设备名称
        if (device != null) {
            vo.setDeviceName(device.getName());
        } else {
            vo.setDeviceName("未知设备");
        }

        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelScheduleForAdvertiser(Long scheduleId, Long advertiserId) {
        // 查询排期


        Schedule schedule = scheduleMapper.selectById(scheduleId);
        if (schedule == null) {
            log.warn("排期不存在，ID: {}", scheduleId);
            return false;
        }

        // 检查排期状态是否可取消
        if ("RUNNING".equals(schedule.getStatus())) {
            log.warn("排期状态为{}，不可取消", schedule.getStatus());
            return false;
        }

        // 检查排期是否属于该广告主
        Advertisement advertisement = advertisementMapper.selectById(schedule.getAdvertisementId());
        // if (advertisement == null || !advertisement.getAdvertiserId().equals(advertiserId)) {
        //     log.warn("广告主(ID:{})无权取消排期(ID:{})", advertiserId, scheduleId);
        //     return false;
        // }

        // 更新排期状态
        schedule.setStatus("CANCELLED");
        schedule.setUpdatedTime(LocalDateTime.now());
        int i = scheduleMapper.updateById(schedule);

        LambdaUpdateWrapper<AdNegotiation> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(AdNegotiation::getId,schedule.getNegotiationId());
        updateWrapper.set(AdNegotiation::getStatus,2);
        adNegotiationMapper.update(null,updateWrapper);

        String title = advertisement.getTitle();
        LambdaQueryWrapper<AdNegotiation> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AdNegotiation::getId, schedule.getNegotiationId());
        AdNegotiation adNegotiation = adNegotiationMapper.selectOne(wrapper);


        LambdaQueryWrapper<Device> deviceQueryWrapper = new LambdaQueryWrapper<>();
        deviceQueryWrapper.eq(Device::getId, adNegotiation.getDeviceId());
        Device device = deviceMapper.selectOne(deviceQueryWrapper);
        handler.sendNotification(advertiserId, "广告"+title+"排期已取消"+LocalDateTime.now());
        handler.sendNotification(adNegotiation.getDeviceOwnerId(), "广告"+title+"与你的设备"+device.getName()+"的排期已经取消"+LocalDateTime.now());
        // 获取当前用户信息
        // 获取当前用户
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext()
                .getAuthentication()
                .getPrincipal();


        // 发送通知给广告主 (如果当前用户是设备主)
        if (!advertisement.getAdvertiserId().equals(loginUser.getUser().getId())) {
            notificationService.createScheduleCanceledNotification(
                    scheduleId,
                    schedule.getAdvertisementId(),
                    advertisement.getAdvertiserId(),
                    loginUser.getUser().getNickname()
            );
        }

        // 发送通知给设备主 (如果当前用户是广告主)
        if (!device.getOwnerId().equals(loginUser.getUser().getId())) {
            notificationService.createScheduleCanceledNotification(
                    scheduleId,
                    schedule.getAdvertisementId(),
                    device.getOwnerId(),
                    loginUser.getUser().getNickname()
            );
        }




        return i==1;

    }

    @Override
    public IPage<AdSchedule> getScheduleList(Page<Schedule> page, Long userId, String status, Long deviceId, String startDate, String endDate) {
        // 获取该用户所有的设备ID
        LambdaQueryWrapper<Device> deviceWrapper = new LambdaQueryWrapper<>();
        deviceWrapper.eq(Device::getOwnerId, userId);
        List<Long> deviceIds = deviceMapper.selectList(deviceWrapper).stream().map(Device::getId).toList();

        if (deviceIds.isEmpty()) {
            // 如果用户没有设备，返回空页面
            return new Page<AdSchedule>().setRecords(List.of());
        }

        LambdaQueryWrapper<Schedule> wrapper = new LambdaQueryWrapper<>();

        // 如果指定了设备ID且该设备属于当前用户，则筛选指定设备
        if (deviceId != null && deviceIds.contains(deviceId)) {
            wrapper.eq(Schedule::getDeviceId, deviceId);
        } else {
            // 否则筛选用户所有设备
            wrapper.in(Schedule::getDeviceId, deviceIds);
        }

        // 根据状态筛选
        if (StringUtils.hasText(status)) {
            wrapper.eq(Schedule::getStatus, status);
        }

        // 根据日期范围筛选
        if (StringUtils.hasText(startDate)) {
            LocalDate startLocalDate = LocalDate.parse(startDate);
            wrapper.ge(Schedule::getStartTime, startLocalDate.atStartOfDay());
        }

        if (StringUtils.hasText(endDate)) {
            LocalDate endLocalDate = LocalDate.parse(endDate);
            wrapper.le(Schedule::getEndTime, endLocalDate.plusDays(1).atStartOfDay());
        }

        // 按创建时间倒序排序
        wrapper.orderByDesc(Schedule::getCreatedTime);

        // 查询结果
        IPage<Schedule> scheduleIPage = scheduleMapper.selectPage(page, wrapper);

        // 转换为 AdSchedule 并填充额外信息
        Page<AdSchedule> resultPage = new Page<>(page.getCurrent(), page.getSize(), scheduleIPage.getTotal());
        List<AdSchedule> adScheduleList = new ArrayList<>(scheduleIPage.getRecords().size());

        for (Schedule schedule : scheduleIPage.getRecords()) {
            // 将 Schedule 转换为 AdSchedule
            AdSchedule adSchedule = convertToAdSchedule(schedule);

            // 获取广告信息
            Advertisement advertisement = advertisementMapper.selectById(schedule.getAdvertisementId());
            if (advertisement != null) {
                adSchedule.setAdvertisementName(advertisement.getTitle());

                // 获取广告主信息
                User advertiser = userService.getUserById(advertisement.getAdvertiserId());
                if (advertiser != null) {
                    adSchedule.setAdvertiserName(advertiser.getUsername());
                }
            }

            // 获取设备信息
            Device device = deviceMapper.selectById(schedule.getDeviceId());
            if (device != null) {
                adSchedule.setDeviceName(device.getName());
            }

            // 解析时间段对象 - 修复类型转换问题
            Object timeSlots = schedule.getTimeSlots();
            if (timeSlots != null) {
                try {
                    // 如果 timeSlots 已经是 List 类型
                    adSchedule.setTimeSlotsObj(objectMapper.convertValue(timeSlots,
                            new TypeReference<List<Map<String, String>>>() {
                            }));
                } catch (Exception e) {
                    log.error("解析时间段JSON失败: {}", e.getMessage(), e);
                }
            }

            adScheduleList.add(adSchedule);
        }

        resultPage.setRecords(adScheduleList);
        return resultPage;
    }

    /**
     * 将 Schedule 对象转换为 AdSchedule 对象
     */
    private AdSchedule convertToAdSchedule(Schedule schedule) {
        AdSchedule adSchedule = new AdSchedule();
        // 复制所有的基本属性
        BeanUtils.copyProperties(schedule, adSchedule);
        return adSchedule;
    }

    @Override
    public boolean updateStatus(Long id, String status, Long userId) {
        Schedule schedule = scheduleMapper.selectById(id);
        if (schedule == null ) {
            throw new BusinessException("排期不存在");
        }

        // 验证设备属于当前用户
        Device device = deviceMapper.selectById(schedule.getDeviceId());
        if (device == null || !device.getOwnerId().equals(userId)) {
            throw new BusinessException("无权更新此排期状态");
        }

        // 验证状态转换的有效性
        validateStatusTransition(schedule.getStatus(), status);

        // 更新状态
        schedule.setStatus(status);
        schedule.setUpdatedTime(LocalDateTime.now());

        boolean updated = scheduleMapper.updateById(schedule)==1;

        // 如果状态更新成功且转为已完成状态，发送通知给广告主
        if (updated && "COMPLETED".equals(status)) {
            Advertisement advertisement = advertisementMapper.selectById(schedule.getAdvertisementId());
            if (advertisement != null) {
                User currentUser = userService.getUserById(userId);
                notificationService.createNotification(
                        advertisement.getAdvertiserId(),
                        "广告排期已完成",
                        String.format("您的广告 \"%s\" 在设备 \"%s\" 上的排期已完成播放。",
                                advertisement.getTitle(), device.getName()),
                        "SCHEDULE_COMPLETED",
                        id,
                        "/advertiser/management"            );
            }
        }

        return updated;
    }

    private void validateStatusTransition(String currentStatus, String newStatus) {
        if (currentStatus.equals(newStatus)) {
            return; // 状态没有变化，直接通过
        }

        // 判断状态转换是否有效
        switch (currentStatus) {
            case "PENDING":
                // 待执行可以转换为执行中或已取消
                if (!"RUNNING".equals(newStatus) && !"CANCELLED".equals(newStatus)) {
                    throw new BusinessException("待执行状态只能转为执行中或已取消");
                }
                break;
            case "RUNNING":
                // 执行中可以转换为已完成或已取消
                if (!"COMPLETED".equals(newStatus) && !"CANCELLED".equals(newStatus)) {
                    throw new BusinessException("执行中状态只能转为已完成或已取消");
                }
                break;
            case "COMPLETED":
            case "CANCELLED":
                // 已完成和已取消状态不能再转换
                throw new BusinessException("当前状态不能更改");
            default:
                throw new BusinessException("无效的当前状态");
        }
    }

    // @Override
    // public Page<Schedule> page(Page<Schedule> page, LambdaQueryWrapper<Schedule> queryWrapper) {
    //     return null;
    // }

    private void validateAdvertisementAndDevice(Long adId, Long deviceId) {
        // 验证广告是否存在且状态正常
        Advertisement ad = advertisementService.getAdvertisementDetail(adId);
        if (ad.getStatus()!=1) {
            throw new BusinessException("广告未通过审核");
        }

        // 验证设备是否存在且状态正常
        Device device = deviceService.getDeviceDetail(deviceId);
        if (device.getStatus()!=1) {
            throw new BusinessException("设备未启用");
        }
    }

    private void validateTimeSlots(List<TimeSlot> timeSlots) {
        if (timeSlots == null || timeSlots.isEmpty()) {
            throw new BusinessException("播放时段不能为空");
        }

        // 验证每个时间段格式
        for (TimeSlot slot : timeSlots) {
            if (slot.getStartTime() == null || slot.getEndTime() == null) {
                throw new BusinessException("时间段开始时间和结束时间不能为空");
            }

            try {
                LocalTime start = LocalTime.parse(slot.getStartTime());
                LocalTime end = LocalTime.parse(slot.getEndTime());
                if (!start.isBefore(end)) {
                    throw new BusinessException("时间段开始时间必须早于结束时间");
                }
            } catch (DateTimeParseException e) {
                throw new BusinessException("时间格式错误，请使用HH:mm格式");
            }
        }

        // 检查时间段之间是否重叠
        timeSlots.sort((a, b) ->
                LocalTime.parse(a.getStartTime()).compareTo(LocalTime.parse(b.getStartTime())));

        for (int i = 0; i < timeSlots.size() - 1; i++) {
            TimeSlot current = timeSlots.get(i);
            TimeSlot next = timeSlots.get(i + 1);

            LocalTime currentEnd = LocalTime.parse(current.getEndTime());
            LocalTime nextStart = LocalTime.parse(next.getStartTime());

            if (!currentEnd.isBefore(nextStart)) {
                throw new BusinessException("播放时段之间存在重叠");
            }   }
    }

}